package loadbalance

import (
	"sync"
	"time"
)

type Endpoint struct {
	sync.RWMutex
	Addr             string
	Port             int
	Weight           int
	MaxFails         int
	FailedTimeoutSec int
	failNum          int
	failTime         int64
	meta             map[string]interface{}
}

func (ep *Endpoint) GetMeta(k string) (v interface{}, ok bool) {
	ep.RLock()
	defer ep.Unlock()
	v, ok = ep.meta[k]
	return
}

func (ep *Endpoint) SetMeta(k string, v interface{}) {
	ep.Lock()
	defer ep.Unlock()
	ep.meta[k] = v
}

func (ep *Endpoint) CheckAvail() bool {
	ep.RLock()
	defer ep.RUnlock()

	if ep.MaxFails <= 0 || ep.FailedTimeoutSec <= 0 {
		return true
	}

	if ep.failNum < ep.MaxFails {
		return true
	}

	now := time.Now().Unix()
	if now > ep.failTime+int64(ep.FailedTimeoutSec) {
		return true
	}

	return false
}

func (ep *Endpoint) FailBack() {
	ep.Lock()
	defer ep.Unlock()

	now := time.Now().Unix()
	if now > ep.failTime+int64(ep.FailedTimeoutSec) {
		ep.failTime = now
		ep.failNum = 1
		return
	}

	if ep.failNum < ep.MaxFails {
		ep.failNum++
	}
}

func NewEndpoint(addr string, port, weight int,
	maxFails, failedTimeoutSec int) *Endpoint {
	return &Endpoint{
		Addr:             addr,
		Port:             port,
		Weight:           weight,
		MaxFails:         maxFails,
		FailedTimeoutSec: failedTimeoutSec,
	}
}
